home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / SpaceballViewer / MyColWheel.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  16.3 KB  |  680 lines

  1. /*
  2.  * Copyright (c) 1990-94 Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  */
  20. /*
  21.  * Copyright (C) 1990-93   Silicon Graphics, Inc.
  22.  *
  23.  _______________________________________________________________________
  24.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  25.  |
  26.  |   $Revision: 1.1018 $
  27.  |
  28.  |   Classes:
  29.  |    MyColorWheel
  30.  |
  31.  |   Author(s)    : Alain Dumesny
  32.  |
  33.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  34.  _______________________________________________________________________
  35.  */
  36.  
  37. #if DEBUG
  38. #include <stream.h>
  39. #endif
  40.  
  41. #include <malloc.h>
  42. #include <math.h>
  43.  
  44. #include <Inventor/Xt/devices/SoXtMouse.h>
  45. #include "MyColorWheel.h"
  46. #include "MyUIRegion.h"
  47.  
  48. #include <GL/gl.h>
  49.  
  50. /*
  51.  * Defines
  52.  */
  53.  
  54. #define CIRCLE        5
  55. #define STRIPES        32
  56. #define SPACE        3
  57. #define MARKER_SLOT 3
  58.  
  59. #define myMapcolor(i, r, g, b)    \
  60.     XColor col;    \
  61.     col.red = r << 8; \
  62.     col.green = g << 8;    \
  63.     col.blue = b << 8;    \
  64.     col.flags = DoRed | DoGreen | DoBlue; \
  65.     col.pixel = i;    \
  66.     XStoreColor(getDisplay(), overlayColorMap, &col);
  67.  
  68.  
  69. ////////////////////////////////////////////////////////////////////////
  70. //
  71. // Public constructor - build the widget right now
  72. //
  73. MyColorWheel::MyColorWheel(
  74.     Widget parent,
  75.     const char *name, 
  76.     SbBool buildInsideParent)
  77.     : SoXtGLWidget(
  78.         parent,
  79.         name, 
  80.         buildInsideParent, 
  81.         SO_GLX_RGB | SO_GLX_OVERLAY, 
  82.         FALSE) // tell GLWidget not to build just yet  
  83. //
  84. ////////////////////////////////////////////////////////////////////////
  85. {
  86.     // In this case, this component is what the app wants, so buildNow = TRUE
  87.     constructorCommon(TRUE);
  88. }
  89.  
  90. ////////////////////////////////////////////////////////////////////////
  91. //
  92. // SoEXTENDER constructor - the subclass tells us whether to build or not
  93. //
  94. MyColorWheel::MyColorWheel(
  95.     Widget parent,
  96.     const char *name, 
  97.     SbBool buildInsideParent, 
  98.     SbBool buildNow)
  99.     : SoXtGLWidget(
  100.         parent,
  101.         name, 
  102.         buildInsideParent, 
  103.         SO_GLX_RGB | SO_GLX_OVERLAY, 
  104.         FALSE) // tell GLWidget not to build just yet  
  105. //
  106. ////////////////////////////////////////////////////////////////////////
  107. {
  108.     // In this case, this component may be what the app wants, 
  109.     // or it may want a subclass of this component. Pass along buildNow
  110.     // as it was passed to us.
  111.     constructorCommon(buildNow);
  112. }
  113.  
  114. ////////////////////////////////////////////////////////////////////////
  115. //
  116. // Called by the constructors
  117. //
  118. // private
  119. //
  120. void
  121. MyColorWheel::constructorCommon(SbBool buildNow)
  122. //
  123. //////////////////////////////////////////////////////////////////////
  124. {
  125.     mouse = new SoXtMouse(ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
  126.  
  127.     // init local vars
  128.     WYSIWYGmode = FALSE;
  129.     hsvColor[0] = hsvColor[1] = 0.0;
  130.     hsvColor[2] = 1.0;
  131.     setGlxSize( SbVec2s(100, 100) );  // default size
  132.  
  133.     // callback lists
  134.     startCallbacks      = new SoCallbackList;
  135.     changedCallbacks     = new SoCallbackList;
  136.     finishCallbacks     = new SoCallbackList;
  137.     interactive = FALSE;
  138.  
  139.     // allocate memory for the geometry/colors
  140.     int num = 1 + CIRCLE * (STRIPES + 1);
  141.     geometry = (SbVec2f *)malloc(num * sizeof(SbVec2f));
  142.     defaultColors = (SbColor *)malloc(num * sizeof(SbColor));
  143.     colors = (SbColor *)malloc(num * sizeof(SbColor));
  144.     
  145.     // ??? reset the geometry to prevent the window manager under PI a362
  146.     // ??? to be killed (redrawing occurs even when window hasn't been
  147.     // ??? mapped yet so those values would be bogus)
  148.     for (int i=0; i<num; i++)
  149.     geometry[i].setValue(0,0);
  150.     
  151.     // make the full intensity colors
  152.     makeWheelColors(defaultColors, 1.0);
  153.     
  154.     // Build the widget tree, and let SoXtComponent know about our base widget.
  155.     if (buildNow) {
  156.     Widget w = buildWidget(getParentWidget());
  157.     setBaseWidget(w);
  158.     }
  159. }
  160.  
  161.  
  162. ////////////////////////////////////////////////////////////////////////
  163. //
  164. //    Destructor.
  165. //
  166.  
  167. MyColorWheel::~MyColorWheel()
  168. //
  169. ////////////////////////////////////////////////////////////////////////
  170. {
  171.     if (geometry != NULL)
  172.     free(geometry);
  173.     if (defaultColors != NULL)
  174.     free(defaultColors);
  175.     if (colors != NULL)
  176.     free(colors);
  177.     
  178.     delete startCallbacks;
  179.     delete changedCallbacks;
  180.     delete finishCallbacks;
  181.     
  182.     delete mouse;
  183. }
  184.  
  185.  
  186. ////////////////////////////////////////////////////////////////////////
  187. //
  188. //    This routine redraws the normal plane color wheel region.
  189. //
  190. // Use: virtual public
  191.  
  192. void
  193. MyColorWheel::redraw()
  194. //
  195. ////////////////////////////////////////////////////////////////////////
  196. {
  197.     if (! isVisible())
  198.     return;
  199.     glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  200.     
  201.     // make a complete drawing
  202.     drawWheelSurrounding();
  203.     drawWheelColors();
  204. }
  205.  
  206.  
  207. ////////////////////////////////////////////////////////////////////////
  208. //
  209. //    This routine redraws the color wheel overlay region (marker).
  210. //
  211. // Use: virtual public
  212.  
  213. void
  214. MyColorWheel::redrawOverlay()
  215. //
  216. ////////////////////////////////////////////////////////////////////////
  217. {
  218.     drawWheelMarker();
  219. }
  220.  
  221.  
  222. ////////////////////////////////////////////////////////////////////////
  223. //
  224. //    Process the passed X event.
  225. //
  226. // Use: virtual public
  227.  
  228. void
  229. MyColorWheel::processEvent(XAnyEvent *xe)
  230. //
  231. ////////////////////////////////////////////////////////////////////////
  232. {
  233.     short x, y;
  234.     XButtonEvent *be;
  235.     XMotionEvent *me;
  236.     SbVec2s size = getGlxSize();
  237.     
  238.     switch (xe->type) {
  239.     case ButtonPress:
  240.         be = (XButtonEvent *) xe;
  241.         if (be->button == Button1) {
  242.         
  243.         // check if click is in color wheel
  244.         x = short(be->x) - cx;
  245.         y = short(size[1] - be->y) - cy;
  246.         if ((x*x + y*y) < ((radius+5)*(radius+5))) {
  247.             startCallbacks->invokeCallbacks(hsvColor);
  248.             interactive = TRUE;
  249.             moveWheelMarker(x, y);
  250.         }
  251.         }
  252.         break;
  253.         
  254.     case ButtonRelease:
  255.         be = (XButtonEvent *) xe;
  256.         if (be->button == Button1 && interactive) {
  257.         interactive = FALSE;
  258.         finishCallbacks->invokeCallbacks(hsvColor);
  259.         }
  260.         break;
  261.         
  262.     case MotionNotify:
  263.         me = (XMotionEvent *) xe;
  264.         if (me->state & Button1Mask)
  265.         moveWheelMarker(short(me->x) - cx, short(size[1] - me->y) - cy);
  266.         break;
  267.     }
  268. }
  269.  
  270.  
  271. ////////////////////////////////////////////////////////////////////////
  272. //
  273. //    This routine sets the color wheel current color.
  274. //
  275. // usage: public
  276.  
  277. void
  278. MyColorWheel::setBaseColor(
  279.     const float hsv[3])
  280. //
  281. ////////////////////////////////////////////////////////////////////////
  282. {
  283.     // check for redraw needs first
  284.     SbBool valueChanged = (hsvColor[2] != hsv[2]);
  285.     SbBool redrawColors = (WYSIWYGmode && valueChanged);
  286.     SbBool redrawMarker = (hsvColor[0]!=hsv[0] || hsvColor[1]!=hsv[1]);
  287.     
  288.     // assign new color
  289.     hsvColor[0] = hsv[0];
  290.     hsvColor[1] = hsv[1];
  291.     hsvColor[2] = hsv[2];
  292.     
  293.     // do wheel colors redraw
  294.     if (redrawColors) {
  295.     makeWheelColors(colors, hsv[2]);
  296.     
  297.     if (! isVisible())
  298.         return;
  299.         glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  300.     drawWheelColors();
  301.     checkMarkerColor();
  302.     }
  303.     
  304.     // do marker redraw
  305.     if (redrawMarker)
  306.     drawWheelMarker();
  307.     
  308.     if (redrawMarker || valueChanged)
  309.     changedCallbacks->invokeCallbacks(hsvColor);
  310. }
  311.  
  312.  
  313. ////////////////////////////////////////////////////////////////////////
  314. //
  315. //    This routine sets the WYSIWYG mode.
  316. //
  317. // usage: public
  318.  
  319. void
  320. MyColorWheel::setWYSIWYG(SbBool flag)
  321. //
  322. ////////////////////////////////////////////////////////////////////////
  323. {
  324.     if (WYSIWYGmode == flag)
  325.     return;
  326.     
  327.     WYSIWYGmode = flag;
  328.     
  329.     // build WYSIWYG colors
  330.     if (WYSIWYGmode)
  331.     makeWheelColors(colors, hsvColor[2]);
  332.     
  333.     // now check if a redraw is needed
  334.     if (hsvColor[2] != 1.0) {
  335.     
  336.     if (! isVisible())
  337.         return;
  338.         glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  339.     drawWheelColors();
  340.     checkMarkerColor();
  341.     }
  342. }
  343.  
  344.  
  345. ////////////////////////////////////////////////////////////////////////
  346. //
  347. // Description:
  348. //      This builds the parent Glx widget, then registers interest
  349. // in mouse events.
  350. //
  351. // Use: protected
  352. Widget
  353. MyColorWheel::buildWidget(Widget parent)
  354. //
  355. ////////////////////////////////////////////////////////////////////////
  356. {
  357.     Widget mgr = SoXtGLWidget::buildWidget(parent);
  358.     
  359.     Widget w = getOverlayWidget() ? getOverlayWidget() : getNormalWidget();
  360.     mouse->enable(w, 
  361.         (XtEventHandler) SoXtGLWidget::eventHandler,
  362.         (XtPointer) this);
  363.     
  364.     return mgr;
  365. }
  366.  
  367.  
  368. ////////////////////////////////////////////////////////////////////////
  369. //
  370. //  This routine is called at window creation time to init the GL state
  371. //
  372. // Use: virtual protected
  373.  
  374. void
  375. MyColorWheel::initOverlayGraphic()
  376. //
  377. ////////////////////////////////////////////////////////////////////////
  378. {
  379.     myMapcolor(MARKER_SLOT, 0, 0, 0);
  380.     blackMarker = TRUE;
  381. }
  382.  
  383.  
  384. ////////////////////////////////////////////////////////////////////////
  385. //
  386. //    This routine is called when window changed size.
  387. //
  388. // Use: virtual private
  389.  
  390. void
  391. MyColorWheel::sizeChanged(const SbVec2s &newSize)
  392. //
  393. ////////////////////////////////////////////////////////////////////////
  394. {
  395.     //
  396.     // recompute things that depend on window size
  397.     //
  398.     short min = (newSize[0] < newSize[1]) ? newSize[0] : newSize[1];
  399.     radius = (min - (4*UI_THICK + 2*SPACE)) / 2;
  400.     cx = newSize[0] / 2;
  401.     cy = newSize[1] / 2;
  402.     
  403.     makeWheelGeometry();
  404.     
  405.     // reset projection
  406.     glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext());
  407.     glViewport(0, 0, newSize[0], newSize[1]);
  408.     glMatrixMode(GL_PROJECTION);
  409.     glLoadIdentity();
  410.     glOrtho(0, newSize[0], 0, newSize[1], -1, 1);
  411.     
  412.     if (getOverlayWindow() != 0) {
  413.     glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
  414.     glViewport(0, 0, newSize[0], newSize[1]);
  415.     glMatrixMode(GL_PROJECTION);
  416.     glLoadIdentity();
  417.     glOrtho(0, newSize[0], 0, newSize[1], -1, 1);
  418.     }
  419. }
  420.  
  421.  
  422. ////////////////////////////////////////////////////////////////////////
  423. //
  424. //    This routine computes the color wheel geometry.
  425. //
  426. // Use: private
  427.  
  428. void
  429. MyColorWheel::makeWheelGeometry()
  430. //
  431. ////////////////////////////////////////////////////////////////////////
  432. {
  433.     SbVec2f *v = geometry;
  434.     float c[STRIPES+1][2];
  435.     int i, j;
  436.     
  437.     // makes the master circle
  438.     float r = radius / float(CIRCLE);
  439.     float angle = 2.0 * M_PI / float(STRIPES);
  440.     c[0][0] = c[STRIPES][0] = r;
  441.     c[0][1] = c[STRIPES][1] = 0.0;
  442.     for (i=1; i<STRIPES; i++) {
  443.     c[i][0] = r * fcos(i*angle);
  444.     c[i][1] = r * fsin(i*angle);
  445.     }
  446.     
  447.     //
  448.     // now build the color wheel geometry
  449.     //
  450.     
  451.     // center point
  452.     (*v)[0] = cx;
  453.     (*v++)[1] = cy;
  454.     
  455.     for (j=1; j<=CIRCLE; j++) {
  456.     for (i=0; i<=STRIPES; i++) {
  457.         (*v)[0] = cx + j * c[i][0];
  458.         (*v++)[1] = cy + j * c[i][1];
  459.     }
  460.     }
  461. }
  462.  
  463.  
  464. ////////////////////////////////////////////////////////////////////////
  465. //
  466. //    This routine computes the color wheel colors given a color 
  467. //  intensity.
  468. //
  469. // Use: private
  470.  
  471. void
  472. MyColorWheel::makeWheelColors(
  473.     SbColor *c, 
  474.     float intensity)
  475. //
  476. ////////////////////////////////////////////////////////////////////////
  477. {
  478.     float hsv[3];
  479.     float Hinc, Sinc;
  480.     int i, j;
  481.     
  482.     hsv[2] = intensity;
  483.     Hinc = 1.0 / float(STRIPES);
  484.     Sinc = 1.0 / float(CIRCLE);
  485.     
  486.     // center color
  487.     (*c)[0] = (*c)[1] = (*c)[2] = intensity; c++;
  488.     
  489.     //
  490.     // now make the wheel colors
  491.     //
  492.     for (j=1; j<=CIRCLE; j++) {
  493.     
  494.     hsv[1] = j * Sinc;
  495.     for (i=0; i<STRIPES; i++) {
  496.         
  497.         hsv[0] = i * Hinc;
  498.         (c++)->setHSVValue(hsv);
  499.     }
  500.     
  501.     // last color is same as first color
  502.     (*c)[0] = (*(c-STRIPES))[0];
  503.     (*c)[1] = (*(c-STRIPES))[1];
  504.     (*c)[2] = (*(c-STRIPES))[2];
  505.     c++;
  506.     }
  507. }
  508.  
  509.  
  510. ////////////////////////////////////////////////////////////////////////
  511. //
  512. //    This routine draws the color wheel surroundings.
  513. //
  514. // Use: private
  515.  
  516. void
  517. MyColorWheel::drawWheelSurrounding()
  518. //
  519. ////////////////////////////////////////////////////////////////////////
  520. {
  521.     glClearColor(.66, .66, .66, 1.0);
  522.     glClear(GL_COLOR_BUFFER_BIT);
  523.     
  524.     // draw outer border
  525.     SbVec2s size = getGlxSize();
  526.     drawDownUIBorders(0, 0, size[0]-1, size[1]-1);
  527. }
  528.  
  529.  
  530. ////////////////////////////////////////////////////////////////////////
  531. //
  532. //    This routine draws the color wheel top part (colors).
  533. //
  534. // Use: private
  535.  
  536. void
  537. MyColorWheel::drawWheelColors()
  538. //
  539. ////////////////////////////////////////////////////////////////////////
  540. {
  541.     SbColor *c1, *c2;
  542.     SbVec2f *v1, *v2;
  543.     int i, j;
  544.     
  545.     //
  546.     // draw center circle as triangle fan
  547.     //
  548.     c1 = (WYSIWYGmode) ? colors : defaultColors;
  549.     v1 = geometry;
  550.     
  551.     glBegin(GL_TRIANGLE_FAN);
  552.     for (i=0; i<(STRIPES+2); i++) {
  553.     glColor3fv((c1++)->getValue());
  554.     glVertex2fv((v1++)->getValue());
  555.     }
  556.     glEnd();
  557.     
  558.     //
  559.     // draw the remaining stripes as quad meshes
  560.     //
  561.     c1 = (WYSIWYGmode) ? colors : defaultColors;
  562.     v1 = geometry;
  563.     c1++; v1++;
  564.     c2 = c1 + STRIPES + 1;
  565.     v2 = v1 + STRIPES + 1;
  566.     
  567.     for (j=1; j<CIRCLE; j++) {
  568.     
  569.     glBegin(GL_QUAD_STRIP);
  570.     for (i=0; i<=STRIPES; i++) {
  571.         glColor3fv((c1++)->getValue());
  572.         glVertex2fv((v1++)->getValue());
  573.         glColor3fv((c2++)->getValue());
  574.         glVertex2fv((v2++)->getValue());
  575.     }
  576.     glEnd();
  577.     }
  578. }
  579.  
  580.  
  581. ////////////////////////////////////////////////////////////////////////
  582. //
  583. //    This routine checks the marker color and changes it if needed.
  584. //
  585. // Use: private
  586.  
  587. void
  588. MyColorWheel::checkMarkerColor()
  589. //
  590. ////////////////////////////////////////////////////////////////////////
  591. {
  592.     if (getOverlayWindow() == 0)
  593.     return;
  594.     
  595.     // map a black or white color depending on background
  596.     
  597.     if (WYSIWYGmode && hsvColor[2]<0.6) {    // should be white
  598.     if (blackMarker) {
  599.         glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
  600.         myMapcolor(MARKER_SLOT, 255, 255, 255);
  601.         blackMarker = FALSE;
  602.     }
  603.     } 
  604.     else {    // should be black
  605.     if (!blackMarker) {
  606.         glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
  607.         myMapcolor(MARKER_SLOT, 0, 0, 0);
  608.         blackMarker = TRUE;
  609.     }
  610.    }
  611. }
  612.  
  613. ////////////////////////////////////////////////////////////////////////
  614. //
  615. //    This routine draws the color marker feedback (in overlay).
  616. //
  617. // Use: private
  618.  
  619. void
  620. MyColorWheel::drawWheelMarker()
  621. //
  622. ////////////////////////////////////////////////////////////////////////
  623. {
  624.     if (getOverlayWindow() == 0 || ! isVisible())
  625.     return;
  626.     glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext());
  627.     
  628.     // find radius and angle from hsv color, from which position is determined.
  629.     short x, y;
  630.     float rad = hsvColor[1] * radius;
  631.     float angle = 2.0 * M_PI * hsvColor[0];
  632.     x = cx + short(rad * fcos(angle));
  633.     y = cy + short(rad * fsin(angle));
  634.     
  635.     //
  636.     // now draw dot in overlay plane
  637.     //
  638.     glClearIndex(0);
  639.     glClear(GL_COLOR_BUFFER_BIT);
  640.     glIndexi(MARKER_SLOT);
  641.     glBegin(GL_LINE_LOOP);
  642.     glVertex2s(x-3, y-3); glVertex2s(x-3, y+3);
  643.     glVertex2s(x+3, y+3); glVertex2s(x+3, y-3);
  644.     glEnd();
  645. }
  646.  
  647. ////////////////////////////////////////////////////////////////////////
  648. //
  649. //    This routine moves the color maker based of mouse position.
  650. //
  651. // Use: private
  652. //
  653. void
  654. MyColorWheel::moveWheelMarker(
  655.     short x, short y)        // wheel center relative coordinates
  656. //
  657. ////////////////////////////////////////////////////////////////////////
  658. {
  659.     // find the saturation based on distance
  660.     float s = fsqrt(x*x + y*y) / float(radius);
  661.     if (s > 1.0)
  662.     s = 1.0;
  663.     
  664.     // now find the hue based on the angle
  665.     float angle = atan2(float(y), float(x));
  666.     if (angle < 0.0)
  667.     angle += 2.0 * M_PI;
  668.     float h = angle / (2.0 * M_PI);
  669.     
  670.     // check if redraw and callback are needed
  671.     if (hsvColor[0] != h || hsvColor[1] != s) {
  672.     
  673.     hsvColor[0] = h;
  674.     hsvColor[1] = s;
  675.     
  676.     drawWheelMarker();
  677.     changedCallbacks->invokeCallbacks(hsvColor);
  678.     }
  679. }
  680.